﻿using System;
using System.Xml;
using System.Xml.Linq;

namespace WolframAlphaSharp
{
    public class QueryResultSerializer
    {
        public QueryResult Deserialize(string xml)
        {
            var doc = XDocument.Parse(xml);

            if( doc.Root == null) throw new XmlException("Document has no root element");

            if( !string.Equals( doc.Root.Name.LocalName, "queryresult", StringComparison.OrdinalIgnoreCase))
            {
                throw new XmlException("Root element is not the expected <queryresult>; actual name: " + doc.Root.Name);
            }

            var result = new QueryResult();
            
            result.Success = doc.Root.ParseAttributeAsBool("success");
            result.Error = doc.Root.ParseAttributeAsBool("error");
            result.NumPods = doc.Root.ParseAttributeAsInt("numpods");
            result.Timing = doc.Root.ParseAttributeAsDouble("timing");
            result.ParseTiming = doc.Root.ParseAttributeAsDouble("parsetiming");
            result.ParseTimedOut = doc.Root.ParseAttributeAsBool("parsetimedout");
            result.Recalculate = doc.Root.ParseAttributeAsUri("recalculate");
            result.Host = doc.Root.ParseAttributeAsUri("host");
            result.Related = doc.Root.ParseAttributeAsUri("related");
            result.Id = doc.Root.GetAttribute("id").Value;
            result.Server = doc.Root.ParseAttributeAsInt("server");
            result.Version = doc.Root.ParseAttributeAsVersion("version");

            // Now parse all the pods
            foreach (var pod in doc.Root.Elements("pod"))
            {
                result.Pods.Add(DeserializePod(pod));
            }
            
            return result;
        }

        internal Pod DeserializePod(XElement x)
        {
            var pod = new Pod();

            pod.Id = x.GetAttribute("id").Value;
            pod.Title = x.GetAttribute("title").Value;
            pod.NumSubPods = x.ParseAttributeAsInt("numsubpods");
            pod.Position = x.ParseAttributeAsInt("position");
            pod.Error = x.ParseAttributeAsBool("error");
            pod.Scanner = x.GetAttribute("scanner").Value;
            pod.Primary = x.ParseAttributeAsBool("primary", false);

            // Check for HTML
            var markup = x.Element("markup");
            if (markup != null) pod.Markup = markup.Value;

            // Get sub pods
            foreach (var subPodElement in x.Elements("subpod"))
            {
                var subPod = DeserializeSubPod(subPodElement);
                pod.SubPods.Add(subPod);
            }

            return pod;
        }

        internal SubPod DeserializeSubPod(XElement x)
        {
            var pod = new SubPod();

            pod.Title = x.GetAttribute("title").Value;

            // Check for plain text
            var plainText = x.Element("plaintext");
            if (plainText != null) pod.PlainText = plainText.Value;

            // Image
            var imageElement = x.Element("img");
            if (imageElement != null)
            {
                var image = new Image();
                image.AltText = imageElement.GetAttribute("alt").Value;
                image.Height = imageElement.GetAttribute("height").Value;
                image.SourceUri = imageElement.ParseAttributeAsUri("src");
                image.Title = imageElement.GetAttribute("title").Value;
                image.Width = imageElement.GetAttribute("width").Value;

                pod.Image = image;
            }

            return pod;
        }
    }
}